package io.github.harmonly.skyblock.manager;

import com.google.gson.JsonObject;
import io.github.harmonly.skyblock.data.PlayerData;
import io.github.harmonly.skyblock.data.ProfileData;
import io.github.harmonly.skyblock.util.JavaUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

/**
 * Manages player data for the Skyblock plugin.
 */
public class DataManager {

    private static final Map<UUID, PlayerData> playerDataMap = new ConcurrentHashMap<>();
    private static final Map<UUID, ProfileData> profileDataMap = new ConcurrentHashMap<>();
    private static final Logger logger = Bukkit.getLogger();

    /**
     * Enables the data manager by creating necessary directories and loading online player data.
     */
    public static void enable() {
        JavaUtil.mkdirs("data/player/", true);
        JavaUtil.mkdirs("data/profile/", true);
        Bukkit.getOnlinePlayers().forEach(DataManager::addPlayerData);
    }

    /**
     * Disables the data manager by saving all player data and clearing the internal map.
     */
    public static void disable() {
        playerDataMap.keySet().forEach(DataManager::savePlayerData);
        playerDataMap.clear();
        profileDataMap.keySet().forEach(DataManager::saveProfileData);
        profileDataMap.clear();
    }

    /**
     * Adds player data to the internal map.
     *
     * @param player The player whose data is to be added.
     */
    public static void addPlayerData(Player player) {
        if (playerDataMap.containsKey(player.getUniqueId())) return;
        JsonObject raw = JavaUtil.readJson("data/player/" + player.getUniqueId() + ".json");
        PlayerData data = new PlayerData(raw, player);
        playerDataMap.put(player.getUniqueId(), data);
        data.init();
    }

    public static Optional<PlayerData> getPlayerData(Player player) {
        return getPlayerData(player.getUniqueId());
    }

    public static Optional<PlayerData> getPlayerData(UUID uuid) {
        return Optional.ofNullable(playerDataMap.getOrDefault(uuid, null));
    }

    public static boolean hasPlayerData(Player player) {
        return hasPlayerData(player.getUniqueId());
    }

    public static boolean hasPlayerData(UUID uuid) {
        return playerDataMap.containsKey(uuid);
    }

    /**
     * Saves player data for a given player.
     *
     * @param player The player whose data is to be saved.
     */
    public static void savePlayerData(Player player) {
        savePlayerData(player.getUniqueId());
    }

    /**
     * Saves player data for a given UUID.
     *
     * @param uuid The UUID of the player whose data is to be saved.
     */
    public static void savePlayerData(UUID uuid) {
        if (!playerDataMap.containsKey(uuid)) return;
        PlayerData data = playerDataMap.get(uuid);
        if (data != null) {
            data.disable();
            JavaUtil.writeJson(data.getRaw(), "data/player/" + uuid + ".json");
            playerDataMap.remove(uuid);
        } else {
            logger.warning("No player data found for UUID: " + uuid);
        }
    }

    public static void addProfileData(Player player, boolean create) {
        UUID uuid = player.getUniqueId();
        if (profileDataMap.containsKey(uuid)) {
            saveProfileData(uuid);
        }
        Optional<PlayerData> playerDataOptional = getPlayerData(player);
        playerDataOptional.ifPresent(playerData -> {
            ProfileData profileData = new ProfileData(
                    create ? new JsonObject() : playerData.getSelectedProfile(),
                    playerData);
            profileDataMap.put(uuid, profileData);
            profileData.init();
        });
    }

    public static Optional<ProfileData> getProfileData(Player player) {
        return getProfileData(player.getUniqueId());
    }

    public static Optional<ProfileData> getProfileData(UUID uuid) {
        return Optional.ofNullable(profileDataMap.getOrDefault(uuid, null));
    }

    public static boolean hasProfileData(Player player) {
        return hasProfileData(player.getUniqueId());
    }

    public static boolean hasProfileData(UUID uuid) {
        return profileDataMap.containsKey(uuid);
    }

    public static void saveProfileData(Player player) {
        saveProfileData(player.getUniqueId());
    }

    public static void saveProfileData(UUID uuid) {
        if (!profileDataMap.containsKey(uuid)) return;
        ProfileData data = profileDataMap.get(uuid);
        if (data != null) {
            data.save();
            profileDataMap.remove(uuid);
        } else {
            logger.warning("No profile data found for UUID: " + uuid);
        }
    }
}
